package com.sniper.datasource;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

/**
 * 数据源切换 对于内部调用的不管用 比如你写了一个扩展了一个接口,
 * 类在调用的时候,虽然在内部调用父接口的方法,但是注解无法获取
 * <p>
 * 增加接口注解，对整个接口起作用---优先级  方法-》接口
 *
 * @author sniper
 */
public class DataSourceAspect {

    private static final Logger logger = LoggerFactory.getLogger(DataSourceAspect.class);

    /**
     * @param point 切点
     * @TODO 根据方法接口查询数据库切换值
     * @TODO 如果方法不存在，就会寻找接口类的切换值
     */
    public void doBefore(JoinPoint point) {

        Object target = point.getTarget();
        StringBuilder buffer = new StringBuilder();
        buffer.append("DataSourceAspect:");
        String className = target.getClass().getName();
        String methodName = point.getSignature().getName();
        buffer.append(className);
        buffer.append(".");
        buffer.append(methodName);


        DataSource dataSource;
        Class<?>[] ifc = target.getClass().getInterfaces();
        Class<?>[] parameterTypes = ((MethodSignature) point.getSignature()).getMethod().getParameterTypes();
        try {
            if (ifc == null || ifc.length == 0) {
                // 设置默认
                DataSourceSwitch.setDefault();
                return;
            }

            Class<?> ifcData = listIfc(ifc[0]);
            Method m = ifc[0].getMethod(methodName, parameterTypes);
            // 注解是否存在此元素上
            //如果方法不存在注解，就去查找接口
            if (m == null || !m.isAnnotationPresent(DataSource.class)) {
                if (ifcData != null && ifcData.isAnnotationPresent(DataSource.class)) {
                    dataSource = ifcData.getAnnotation(DataSource.class);
                    DataSourceSwitch.setDataSource(dataSource.value());
                    DataSourceSwitch.setDataClass(buffer.toString());
                } else {
                    DataSourceSwitch.setDefault();
                }
                return;
            }
            dataSource = m.getAnnotation(DataSource.class);
            DataSourceSwitch.setDataSource(dataSource.value());
            DataSourceSwitch.setDataClass(buffer.toString());

        } catch (NoSuchMethodException e) {
            e.printStackTrace();
            DataSourceSwitch.setDefault();
            logger.error(buffer.toString(), e);
        }
    }

    /**
     * 查找接口的接口
     *
     * @param ifc
     */
    private Class<?> listIfc(Class<?> ifc) {

        List<Class> ifcs = new ArrayList<>();
        listIf(ifc.getInterfaces(), ifcs);
        if (ifcs.size() > 0) {
            return ifcs.iterator().next();
        }
        return null;

    }

    /**
     * 查看接口的所有父级
     * 遇见第一个包含DataSource停止
     *
     * @param ifc
     * @param ifcs
     */
    private void listIf(Class<?>[] ifc, List<Class> ifcs) {

        if (ifc != null && ifc.length > 0) {
            if (ifc[0].isAnnotationPresent(DataSource.class)) {
                ifcs.add(ifc[0]);
            } else {
                listIf(ifc[0].getInterfaces(), ifcs);
            }
        }
    }
}
